import {
  Controller,
  Post,
  UploadedFile,
  UseInterceptors,
  Get,
  Param,
  Delete,
  HttpCode,
  HttpStatus,
  Res,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { UploadService } from './upload.service';
import {
  ApiBody,
  ApiConsumes,
  ApiMovedPermanentlyResponse,
  ApiResponse,
  ApiTags,
  IntersectionType,
} from '@nestjs/swagger';
import { FileDto, UploadDto } from './dtos/upload.dto';
import {
  ApiCommonDataBooleanResponse,
  ApiCommonDataResponse,
} from 'src/decorators/api-common-data-response.decorator';
import { diskStorage, memoryStorage } from 'multer';
import { Public } from 'src/decorators/publics.decorator';
import fs from 'fs';
import { ExtraModelDto } from 'src/dtos/extra-model.dto';
import { Response } from 'express';
import { uniqueFilename, uploadDatePath } from 'src/utils';

@ApiTags('upload')
@Controller('upload')
export class UploadController {
  constructor(private uploadService: UploadService) {}

  @Public()
  @HttpCode(HttpStatus.OK)
  @Post('file')
  @UseInterceptors(
    FileInterceptor('file', {
      storage: diskStorage({
        // 配置文件保存的路径
        // destination: /*process.cwd()*/ './uploads',
        destination: async (req, file, callback) => {
          try {
            const up = uploadDatePath();

            // 使用异步方法创建目录
            await fs.promises.mkdir(up, { recursive: true });

            callback(null, up);
          } catch (err) {
            callback(err, null);
          }
        },
        // 配置文件保存的文件名
        filename: (req, file, callback) => {
          callback(null, uniqueFilename(file));
        },
      }),
    }),
  )
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    description: '文件上传',
    type: UploadDto,
  })
  @ApiCommonDataResponse(IntersectionType(FileDto, ExtraModelDto))
  async uploadFile(@UploadedFile() file: Express.Multer.File) {
    /*
        {
            fieldname: 'file',
            originalname: 'ChMkJlbKw6qIfw7IAAabqdbC5xQAALG6gOURAsABpvB475.jpg',
            encoding: '7bit',
            mimetype: 'image/jpeg',
            destination: './uploads',
            filename: 'file-1696754797729-817402961.jpg',
            path: 'uploads\\file-1696754797729-817402961.jpg',
            size: 433065
        }
    */

    return this.uploadService.uploadFile(file);
  }

  @Public()
  @HttpCode(HttpStatus.OK)
  @Post('oss/file')
  @UseInterceptors(
    FileInterceptor('file', {
      storage: memoryStorage(),
    }),
  )
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    description: '文件上传',
    type: UploadDto,
  })
  @ApiCommonDataResponse(IntersectionType(FileDto, ExtraModelDto))
  async uploadOssFile(@UploadedFile() file: Express.Multer.File) {
    /*
        {
            fieldname: 'file',
            originalname: 'ChMkJlbKw6qIfw7IAAabqdbC5xQAALG6gOURAsABpvB475.jpg',
            encoding: '7bit',
            mimetype: 'image/jpeg',
            buffer: '<Buffer ff d8 ff e0 ... 19233 more bytes>',
            size: 433065
        }
    */
    return this.uploadService.uploadOssFile(file);
  }

  @Public()
  @HttpCode(HttpStatus.OK)
  @Get(':filename')
  @ApiResponse({
    status: 200,
    description: '返回上传的文件',
    content: {
      'image/jpeg': {},
      'image/png': {},
      'image/gif': {},
      'application/octet-stream': {},
    },
  })
  async getFileUrl(@Res() res: Response, @Param('filename') filename: string) {
    // return this.ossService.getFileUrl(fileName);
    const { contentType, filePath } =
      await this.uploadService.getFileUrl(filename);

    // 设置响应头
    res.setHeader('Content-Type', contentType);

    // 返回图片文件
    res.sendFile(filePath);
  }

  @Public()
  @HttpCode(HttpStatus.MOVED_PERMANENTLY)
  @Get('oss/:filename')
  @ApiMovedPermanentlyResponse({
    description: '跳转到 oss 文件',
  })
  async getOssFileUrl(
    @Res() res: Response,
    @Param('filename') filename: string,
  ) {
    // return this.ossService.getFileUrl(fileName);
    const url = await this.uploadService.getOssFileUrl(filename);

    // 设置 301 永久跳转
    res.redirect(301, url);
  }

  @Public()
  @HttpCode(HttpStatus.OK)
  @Delete(':filename')
  @ApiCommonDataBooleanResponse()
  async deleteFile(@Param('filename') filename: string) {
    // await this.ossService.deleteFile(fileName);
    return this.uploadService.deleteFile(filename, false);
  }

  @Public()
  @HttpCode(HttpStatus.OK)
  @Delete('oss/:filename')
  @ApiCommonDataBooleanResponse()
  async deleteOssFile(@Param('filename') filename: string) {
    return this.uploadService.deleteOssFile(filename, false);
  }
}
